package tech.yixiyun.framework.kuafu.domain;


import tech.yixiyun.framework.kuafu.domain.annotation.Column;
import tech.yixiyun.framework.kuafu.domain.annotation.GenerateFrom;
import tech.yixiyun.framework.kuafu.domain.annotation.KeyType;
import tech.yixiyun.framework.kuafu.kits.ClassKit;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Domain 全局类，通过它管理所有的Domain
 */
public class DomainContext {

    private static final ConcurrentHashMap<String, DomainDefinition> domainMap = new ConcurrentHashMap<>();


    /**
     * 注册Domain类
     * @param domainClass
     */
    public static DomainDefinition register(Class domainClass) {
        DomainDefinition definition = new DomainDefinition(domainClass);

        if(domainMap.putIfAbsent(domainClass.getName(), definition) != null) {

            throw new RuntimeException(domainClass.getName() + " 在DomainContext中已注册，不可重复注册");
        }


        List<Field> fields = ClassKit.getFields(domainClass);
        List<String> primaryColumns = new ArrayList<>();
        for (Field field : fields) {
            Column columnAnno = field.getDeclaredAnnotation(Column.class);
            //临时字段不能在这里忽略,会导致查询是无法赋值
            //if (columnAnno != null && columnAnno.isTemp()) continue;

            int modifiers = field.getModifiers();
            if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)
                    || Modifier.isPublic(modifiers)) {
                continue;
            }
            ColumnDefinition column = new ColumnDefinition(field, columnAnno);
            //如果是主键
            if (column.getIsPrimaryKey()) {
                primaryColumns.add(column.getField().getName());
            }
            definition.addColumn(column);
        }
        List<KeyDefinition> keys = definition.getKeys();
        //看一下是否已经在Domain上声明primary key了
        KeyDefinition primaryKey = null;
        if (keys != null) {
            for (KeyDefinition key : keys) {
                if (key.getType() == KeyType.PRIMARY) {
                    primaryKey = key;
                    primaryKey.setName(""); //主键没有名字
                    break;
                }
            }
        }
        //没的话，看看@Column 有没有声明主键的
        if (primaryKey == null) {
            if (primaryColumns.size() > 0) {
                primaryKey = new KeyDefinition();
                primaryKey.setName("");
                primaryKey.setType(KeyType.PRIMARY);
                primaryKey.setColumns(primaryColumns.toArray(String[]::new));
                definition.addKey(primaryKey);
            } else { //没有，就找找有没有叫id的字段
                ColumnDefinition id = definition.getColumnMap().get("id");
                if (id != null) {
                    primaryKey = new KeyDefinition();
                    primaryKey.setName("");
                    primaryKey.setType(KeyType.PRIMARY);
                    primaryKey.setColumns(new String[]{"id"});
                    definition.addKey(primaryKey);
                }
            }
        }

        if (primaryKey != null) {
            String[] columns = primaryKey.getColumns();
            for (String columnName : columns) {
                ColumnDefinition column = definition.getColumnMap().get(columnName);
                column.setIsPrimaryKey(true);
                //主键要not null
                column.setIsNotNull(true);
                if (GenerateFrom.AUTOINCREMENT == column.getGenerateFrom()) {
                    definition.setAutoIncrementColumn(column.getName());
                }
            }
        }

        return definition;
    }

    public static DomainDefinition getDomainDefinition(String key) {
        return domainMap.get(key);
    }

    public static DomainDefinition getDomainDefinition(Class domainClass) {
        return domainMap.get(domainClass.getName());
    }

    /**
     * 移除某个Domain类的注册
     * @param domainClass
     */
    public static void unregister(Class domainClass) {
        domainMap.remove(domainClass.getName());
    }


    /**
     * 获取所有的domain定义
     * @return
     */
    public static List<DomainDefinition> getAllDomainDefinition() {
        List<DomainDefinition> list = new ArrayList<>(domainMap.size());
        domainMap.values().forEach(list::add);
        return list;
    }

    /**
     * 获取所有单表Domain定义
     * @return
     */
    public static List<DomainDefinition> getAllSingleDomainDefinition() {
        List<DomainDefinition> list = new ArrayList<>();
        domainMap.values().forEach(item -> {
            if (item.getIsSplit() == false) {
                list.add(item);
            }
        });
        return list;
    }
    /**
     * 获取所有分表Domain定义
     * @return
     */
    public static List<DomainDefinition> getAllMultiDomainDefinition() {
        List<DomainDefinition> list = new ArrayList<>();
        domainMap.values().forEach(item -> {
            if (item.getIsSplit()) {
                list.add(item);
            }
        });
        return list;
    }


}
